package cn.cosmosx.base.generator.mp;

import cn.cosmosx.controller.sys.param.GeneratorParam;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 代码生成器
 *
 * @author gengzhy
 */
@Component
public class AutoCodeGenerator {
    @Resource
    private DataSource dataSource;

    /**
     * 代码生成
     *
     * @param param - param 中的tables:需要生成代码的表（传入表名，若多张表，则以","分隔;若生成全部，则传入“all”）
     */
    public void generate(GeneratorParam param) {
        File projectPath = new File(param.getProjectPath());
        if (!projectPath.exists() && projectPath.mkdirs());
        File mapperXmlPath = new File(param.getMapperXmlPath());
        if (!mapperXmlPath.exists() && mapperXmlPath.mkdirs());
        // 数据库配置
        FastAutoGenerator.create(new DataSourceConfig.Builder(dataSource))
                // 全局配置
                .globalConfig((scanner, builder) -> {
                    builder.author(param.getAuthor())
                            // 覆盖已生成文件
                            .fileOverride()
                            // 指定输出目录
                            .outputDir(param.getProjectPath())
                            // 开启 swagger 模式
                            .enableSwagger()
                            // 禁止打开输出目录
                            .disableOpenDir()
                            // 时间策略
                            .dateType(DateType.TIME_PACK)
                            // 类注释日期的格式
                            .commentDate("yyyy-MM-dd HH:mm:ss").build();
                })
                // 包配置
                .packageConfig((scanner, builder) -> {
                    // 父包名
                    builder.parent(param.getParentPkg())
                            // 模块名
                            .moduleName(param.getModuleName())
                            // Entity 包名
                            .entity("entity")
                            // Service 包名
                            .service("service")
                            //	Service Impl 包名
                            .serviceImpl("impl")
                            // Controller 包名
                            .controller("controller")
                            // Mapper 包名
                            .mapper("mapper")
                            // MapperXML 包名
                            .xml("mapper")
                            // 路径配置信息
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, param.getMapperXmlPath()));
                })
                //策略配置
                .strategyConfig((scanner, builder) -> {
                    // 增加表匹配(内存过滤)，	include 与 exclude 只能配置一项
                    builder.addInclude(getTables(param.getTables()))
                            // 	增加表排除匹配(内存过滤)，	include 与 exclude 只能配置一项
                            // .addExclude("请输入要忽略的表名，多个英文逗号分隔？")
                            // 	增加过滤表后缀
                            .addTableSuffix("")
                            // 	增加过滤表前缀
                            .addTablePrefix("")
                            // service 策略配置
                            .serviceBuilder()
                            // 	格式化文件名称
                            .formatServiceFileName("%sService")
                            .formatServiceImplFileName("%sServiceImpl")

                            // 实体策略配置
                            .entityBuilder()
                            // 数据库表映射到实体的命名策略（下划线转驼峰命名）
                            .naming(NamingStrategy.underline_to_camel)
                            // 数据库表字段映射到实体的命名策略（下划线转驼峰命名）
                            .columnNaming(NamingStrategy.underline_to_camel)
                            // 开启 lombok 模型
                            .enableLombok()
                            // 开启生成实体时生成字段注解
                            .enableTableFieldAnnotation()
                            // 开启链式模型
                            .enableChainModel()
                            // 设置乐观锁数据库表字段名称
                            .versionColumnName("version")
                            // 设置乐观锁实体属性字段名称
                            .versionPropertyName("version")
                            // 逻辑删除数据库字段名称
                            .logicDeleteColumnName("deleted")
                            // 逻辑删除实体属性名称
                            .logicDeletePropertyName("deleted")
                            // 父类名称（含包名）
                            .superClass(param.getSuperEntityName())
                            // 添加父类公共字段
                            .addSuperEntityColumns("creator", "create_time", "updater", "update_Time", "version", "deleted")
                            // 指定生成的主键的ID类型（雪花算法）
                            .idType(IdType.ASSIGN_ID)

                            // controller 策略配置
                            .controllerBuilder().formatFileName("%sController")
                            // 开启生成@RestController 控制器
                            .enableRestStyle()
                            // 开启驼峰转连字符
                            .enableHyphenStyle()


                            // 	mapper 策略配置
                            .mapperBuilder()
                            // 设置父类
                            .superClass(BaseMapper.class)
                            .formatMapperFileName("%sMapper")
                            .enableMapperAnnotation()
                            .formatXmlFileName("%sMapper")
                            // 生成公共字段映射及字段
                            .enableBaseResultMap()
                            // 生成公共数据库字段
                            .enableBaseColumnList();
                })
                // 使用Freemarker引擎模板，默认的是Velocity引擎模板
                .templateEngine(new FreemarkerTemplateEngine()).execute();
    }

    /**
     * 处理 all 情况
     */
    private List<String> getTables(String tables) {
        return "all".equalsIgnoreCase(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
    }
}

